package jdec.jdt.ls.decompiler.common.source.attach;

import java.nio.file.Files;
import java.nio.file.Path;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ls.core.internal.commands.SourceAttachmentCommand.SourceAttachmentResult;

import jdec.jdt.ls.decompiler.common.source.attach.SourceAttachmentCommand.SourceAttachmentAttribute;

public class AttachSourceHandler implements IAttachSourceHandler {

    private static final String JAR_SUFFIX = ".jar";

    private static final String[] SOURCE_JAR_SUFFIX = new String[] {"_src.jar", "-sources.jar"};

    @Override
    public boolean syncAttachSource(final IPackageFragmentRoot root) {
        try {
            IClasspathEntry entry = root.getRawClasspathEntry();
            if (entry == null) {
                return false;
            }

            int kind = entry.getEntryKind();
            if (kind == IClasspathEntry.CPE_LIBRARY || kind == IClasspathEntry.CPE_VARIABLE) {
                Path jarPath = entry.getPath().toFile().toPath();
                IPath detectSources = detectSources(jarPath);
                if (detectSources == null) {
                    return false;
                }

                Path sourceAttachmentPath = detectSources.toFile().toPath();
                String sourceAttachmentEncoding = detectSourceAttachmentEncoding(jarPath);
                SourceAttachmentAttribute attr = new SourceAttachmentAttribute(jarPath.toFile().getAbsolutePath(),
                        sourceAttachmentPath.toFile().getAbsolutePath(), sourceAttachmentEncoding);
                SourceAttachmentResult sourceAttachmentResult = SourceAttachmentCommand.updateSourceAttachment(root, attr, new NullProgressMonitor());
                if (sourceAttachmentResult.errorMessage == null) {
                    return true;
                }
            }
        } catch (JavaModelException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return false;
    }

    public static IPath detectSources(Path file) {
        String filename = file.getFileName().toString();
        // skip classes on detectSources
        if (!filename.endsWith(JAR_SUFFIX)) {
            return null;
        }

        // better approach would be to (also) resolve sources using Maven central, or anything smarter
        // really
        for (String suffix : SOURCE_JAR_SUFFIX) {
            String sourceName = filename.substring(0, filename.lastIndexOf(JAR_SUFFIX)) + suffix;
            Path sourcePath = file.getParent().resolve(sourceName);
            if (Files.isRegularFile(sourcePath)) {
                return new org.eclipse.core.runtime.Path(sourcePath.toString());
            }
        }
        return null;
    }

    public static String detectSourceAttachmentEncoding(Path file) {
        String filename = file.getFileName().toString();
        // better approach would be to (also) resolve sources using Maven central, or anything smarter
        // really
        for (String suffix : SOURCE_JAR_SUFFIX) {
            String sourceName = filename.substring(0, filename.lastIndexOf(JAR_SUFFIX)) + suffix;
            Path sourcePath = file.getParent().resolve(sourceName);
            if (Files.isRegularFile(sourcePath)) {
                if (SOURCE_JAR_SUFFIX[0].equals(suffix)) {
                    return "gb18030";
                }
                return "utf-8";
            }
        }
        return "utf-8";
    }

    @Override
    public boolean syncAttachSource(IClassFile classFile) {
        try {
            Path jarPath = classFile.getPath().toFile().toPath();
            IPath sourcePath = detectSources(jarPath);
            if (sourcePath == null) {
                return false;
            }

            String sourceAttachmentPath = sourcePath.toFile().getAbsolutePath();
            String sourceAttachmentEncoding = detectSourceAttachmentEncoding(jarPath);

            IPackageFragment pkgFrag = (IPackageFragment) classFile.getParent();
            IPackageFragmentRoot root = (IPackageFragmentRoot) pkgFrag.getParent();

            IClasspathEntry entry = root.getRawClasspathEntry();
            if (entry == null) {
                return false;
            }

            SourceAttachmentAttribute attr =
                    new SourceAttachmentAttribute(jarPath.toFile().getAbsolutePath(), sourceAttachmentPath, sourceAttachmentEncoding);
            SourceAttachmentResult sourceAttachmentResult = SourceAttachmentCommand.updateSourceAttachment(root, attr, new NullProgressMonitor());
            if (sourceAttachmentResult.errorMessage == null) {
                return true;
            }
        } catch (JavaModelException e) {
            e.printStackTrace();
        }

        return false;
    }

}
